<script setup lang="ts">
import {ref, useTemplateRef, onMounted, onUnmounted, nextTick} from "vue";
import type { Props, TreeData} from "./index.ts";
import { Close } from "@element-plus/icons-vue";
import ElTree from "element-plus/es/components/tree/index";
import type {TreeInstance} from "element-plus/es/components/tree/src/instance";

defineOptions({
  name: "TreeSelect"
})

const props = defineProps<Props<TreeData[]>>();
const emit = defineEmits(["getData"]);
const choseRobot = ref<boolean>(false); // 控制下拉显示隐藏
const isFocus = ref<boolean>(false); // 聚焦
const selectNode = ref<any[]>([]); // 选中的数据
const elTreeRef = useTemplateRef<TreeInstance | undefined>("elTreeRef"); // tree实例
const treeProps = { // tree组件配置
  label: props.definedProps.label || "label",
  children: props.definedProps.children || "children"
};

/**
 * 设置节点选中
 */
const setCheckedNodesHandler = async () => {
  await nextTick();
  if (Array.isArray(elTreeRef.value)) {
    elTreeRef.value.forEach((item) => {
      item.setCheckedNodes(selectNode.value);
    });
  } else {
    elTreeRef.value?.setCheckedNodes(selectNode.value);
  }
};

/**
 * 聚焦处理
 */
const focusHandler = () => {
  isFocus.value = true;
  choseRobot.value = true;
  if (selectNode.value.length <= 0 && !elTreeRef.value) return;
  setCheckedNodesHandler();
}

/**
 * 关闭标签处理
 * @param node
 */
const closeHandler = (node: any) => {
  choseRobot.value = true;
  const index = selectNode.value.findIndex((item) => item[treeProps.label] === node[treeProps.label]);
  if (index > -1) {
    selectNode.value.splice(index, 1);
    emit("getData", selectNode.value);
  }
  setCheckedNodesHandler();
};

/**
 * 机器人选择
 * @param node 当前节点数据
 * @param isCurrent 当前是否被选中共
 * @param isChild 节点下子集是否被选中
 */
const handleCheckChange = (node: any, isCurrent: boolean, isChild: boolean) => {
  const index = selectNode.value.findIndex((item) => item[treeProps.label] === node[treeProps.label]);
  // todo 有可能机器人字段中本来存在children  node[treeProps.children]?.length === 0
  if (isCurrent && !node[treeProps.children] && index < 0) { // index 处理触发来源，设置节点选中会触发
    selectNode.value.push(node);
  }
  if (!isCurrent) {
    if (index > -1) {
      selectNode.value.splice(index, 1);
    }
  }
  // 相同节点设置选中与否
  if(Array.isArray(elTreeRef.value) && !node[treeProps.children]) {
    elTreeRef.value.forEach((treeRef) => {
      treeRef.setChecked(node, isCurrent, false);
    });
  }
  emit("getData", selectNode.value);
}

/**
 * 判断鼠标点击是否再指定dom中，否则关闭下拉
 * @param e
 */
const handleClickOutside = (e: MouseEvent) => {
  const isInput = e.target instanceof HTMLElement && e.target.closest('.robotSelect');
  const isMenu = e.target instanceof HTMLElement && e.target.closest('#robotList');
  if (!isInput && !isMenu) {
    choseRobot.value = false;
  }
}

/**
 * 生命周期-挂在
 */
onMounted(() => {
  window.addEventListener('click', handleClickOutside);
});

/**
 * 生命周期-销毁
 */
onUnmounted(() => {
  window.removeEventListener('click', handleClickOutside);
});
</script>

<template>
  <div class="input-select" :class="{ 'is-focus': isFocus }">
    <div class="input-container">
      <template v-if="selectNode.length > 0">
        <template v-for="(item, index) in selectNode" :key="index">
          <span class="input-tag">
            <span class="tag-content">{{ item[treeProps.label] }}</span>
            <span class="tag-close" @click.stop="closeHandler(item)">
              <el-icon><Close /></el-icon>
            </span>
          </span>
        </template>
      </template>
      <div class="input-wrapper">
        <input
          class="input-inner robotSelect"
          @focus.stop="focusHandler"
          @blur.stop="isFocus = false"
        />
      </div>
    </div>
  </div>
  <transition name="el-zoom-in-top">
    <div
      id="robotList"
      ref="robotList"
      v-if="choseRobot"
      class="bg-white absolute w-100% top-56px rounded-20px p-15px box-border max-h-493px z-[99] border-1px-solid-#717EEA overflow-auto"
    >
      <p class="pb-10px pl-6px text-14px">所有</p>
      <template v-if="data.length > 0">
        <div class="robotItem" v-for="(item, index) in data" :key="index">
        <div class="all pl-6px" v-if="!item[treeProps.label]">{{ item[treeProps.label] }}</div>
        <div class="pt-10px" v-else>
          <p class="pb-10px pl-6px text-14px">{{ item[treeProps.label] }}</p>
          <el-tree
            ref="elTreeRef"
            :highlight-current="true"
            :render-after-expand="false"
            :check-on-click-leaf="false"
            style="max-width: 600px; width: 100%"
            :data="item.children"
            show-checkbox
            :node-key="treeProps.label"
            :props="treeProps"
            @check-change="handleCheckChange"
          >
            <template v-if="!isCount" #default="{ _, data }">
              <slot v-bind="data">
                {{ data[treeProps.label] }}{{ data[treeProps.children] ? " ("+ data[treeProps.children].length + ")" : ""}}
              </slot>
            </template>
          </el-tree>
        </div>
      </div>
      </template>
      <template v-else><p style="display: flex;align-items: center; justify-content: center">暂无数据</p></template>
    </div>
  </transition>
</template>

<style scoped lang="less">
:deep(.el-select__wrapper) {
  overflow: auto;
}
.input-select {
  width: 100%;
  height: 49px;
  border-radius: 8px;
  overflow: auto;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  cursor: pointer;
  font-size: 14px;
  min-height: 32px;
  line-height: 24px;
  transform: translateZ(0px);
  box-shadow: 0 0 0 1px #dcdfe6 inset;
  padding: 4px;
  transition: all 0.3s;
  .input-container {
    position: relative;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    height: 100%;
    max-width: 100%;
    min-width: 0px;
    flex: 1 1 0%;
    gap: 6px;
    .input-tag {
      background-color: rgb(243.9, 244.2, 244.8);
      color: #909399;
      display: inline-flex;
      justify-content: center;
      align-items: center;
      vertical-align: middle;
      height: 24px;
      font-size: 12px;
      line-height: 1;
      box-sizing: border-box;
      border-color: rgb(232.8, 233.4, 234.6);
      padding: 0px 9px;
      padding-right: 5px;
      border-width: 1px;
      border-style: solid;
      border-radius: 4px;
      white-space: nowrap;
      .tag-content {
        font-size: 12px;
        min-width: 0px;
        line-height: normal;
        text-overflow: ellipsis;
        overflow: hidden;
        white-space: nowrap;
      }
      .tag-close {
        margin-left: 6px;
        border-radius: 50%;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        &:hover {
          color: #FFFFFF;
          background-color: #909399;
        }
      }
    }
    .input-wrapper{
      flex: 1 1 0%;
      .input-inner {
        min-width: 11px;
        color: #606266;
        font-size: inherit;
        font-family: inherit;
        line-height: inherit;
        appearance: none;
        width: 100%;
        background-color: transparent;
        border-width: initial;
        border-style: none;
        border-color: initial;
        border-image: initial;
        outline: none;
        padding: 0px;
      }
    }
  }
}
.is-focus {
  box-shadow: 0 0 0 1px rgba(126, 99,255, 1) !important;
}
</style>